package com.park.microprofile.converter;

import org.eclipse.microprofile.config.spi.Converter;

import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * 转换器集合
 *
 * @author Aaron
 * @date 2021/7/13 22:24
 */
public class Converters implements Iterable<Converter<?>> {
    /**
     * 默认转换器优先级
     */
    private static final int DEFAULT_PRIORITY = 100;

    /**
     * 存储转换器的容器
     */
    private final Map<Class<?>, PriorityQueue<PrioritizedConverter<?>>> converterMap = new HashMap<>();

    /**
     * 类加载器
     */
    private ClassLoader classLoader;

    /**
     * 是否加载过
     */
    private boolean isDiscoveredConverters = false;

    public Converters(ClassLoader classLoader) {
        this.classLoader = classLoader;
        // 加载 SPI 配置
        discoveredConverters();
    }

    /**
     * 设置类加载器
     *
     * @param classLoader classLoader
     */
    public void setClassLoader(ClassLoader classLoader) {
        this.classLoader = classLoader;
    }

    /**
     * 通过 SPI 机制加载转换器
     */
    public void discoveredConverters() {
        // 为了防止重复加载转换器，需要设置个开关，如果加载过了不需要重复加载
        if (isDiscoveredConverters) {
            return;
        }

        addConverters(ServiceLoader.load(Converter.class, this.classLoader));
        isDiscoveredConverters = true;
    }

    /**
     * 批量添加转换器
     */
    public void addConverters(Converter<?>... converters) {
        addConverters(Arrays.asList(converters));
    }

    private void addConverters(Iterable<Converter> converters) {
        converters.forEach(this::addConverter);
    }

    /**
     * 添加转换器
     */
    public void addConverter(Converter<?> converter) {
        // 解析转换器的类型
        Class<?> typeClass = resolveConverterType(converter);

        // 添加转换器
        addConverter(converter, DEFAULT_PRIORITY, typeClass);
    }

    public PriorityQueue<PrioritizedConverter<?>> getConverter(Class<?> classType) {
        return converterMap.get(classType);
    }

    /**
     * 解析转换器的泛化类型
     */
    private Class<?> resolveConverterType(Converter<?> converter) {
        // 检查 Converter 的合法性
        checkConverter(converter);

        Class<?> convertedType = null;

        for (Type superInterface : converter.getClass().getGenericInterfaces()) {
            convertedType = resolveConverterType(superInterface);
            if (convertedType != null) {
                break;
            }
        }

        return convertedType;
    }

    private Class<?> resolveConverterType(Type type) {
        Class<?> convertedType = null;
        if (type instanceof ParameterizedType) {
            ParameterizedType pType = (ParameterizedType) type;
            if (pType.getRawType() instanceof Class) {
                Class<?> rawType = (Class) pType.getRawType();
                if (Converter.class.isAssignableFrom(rawType)) {
                    Type[] arguments = pType.getActualTypeArguments();
                    if (arguments.length == 1 && arguments[0] instanceof Class) {
                        convertedType = (Class) arguments[0];
                    }
                }
            }
        }
        return convertedType;
    }

    /**
     * 手动添加转换器
     *
     * @param converter     转换器
     * @param priority      优先级编号
     * @param convertedType 转换器类型
     */
    public void addConverter(Converter<?> converter, int priority, Class<?> convertedType) {
        // 如果不存在，则添加一个优先级队列
        PriorityQueue<PrioritizedConverter<?>> prioritizedConverters =
                converterMap.computeIfAbsent(convertedType, p -> new PriorityQueue<>());

        // 添加 转换器
        prioritizedConverters.offer(new PrioritizedConverter<>(converter, priority));
    }

    private void checkConverter(Converter<?> converter) {
        Class<?> converterClass = converter.getClass();
        if (converterClass.isInterface()) {
            throw new IllegalArgumentException("类型转换器的实现必须不能是接口!");
        }
        if (Modifier.isAbstract(converterClass.getModifiers())) {
            throw new IllegalArgumentException("类型转换器的实现必须不能是抽闲类!");
        }
    }

    @Override
    public Iterator<Converter<?>> iterator() {

        List<Converter<?>> converters = new LinkedList<>();

        for (PriorityQueue<PrioritizedConverter<?>> prioritizedConverters : converterMap.values()) {
            for (PrioritizedConverter<?> prioritizedConverter : prioritizedConverters) {
                converters.add(prioritizedConverter.getConverter());
            }
        }
        return converters.iterator();
    }
}
